<template>
  <div class="menu d-flex flex-column">
    <div class="logo d-flex j-center a-center">
      <img src="@/assets/img/logo.svg" />
    </div>
    <el-scrollbar class="list flex-1">
      <el-collapse v-model="activeNames">
        <el-collapse-item
          v-for="collapse in menuList"
          :title="collapse.title"
          :name="collapse.key"
          :key="collapse.key"
        >
          <template #title v-if="collapse.key === 'createdSongs'">
            <div class="d-flex a-center">
              <div class="pd-r70">{{ collapse.title }}</div>
              <el-icon @click.stop="addSongSheet"><Plus /></el-icon>
            </div>
          </template>
          <div
            v-for="(item, index) in collapse.children"
            :key="index"
            class="pointer menu-item font-15"
            @click="menuClick(item)"
            @click.right.prevent="clickRight($event, item)"
            :class="{ active: item.key === currentNode.key }"
          >
            {{ item.title }}
          </div>
        </el-collapse-item>
      </el-collapse>
    </el-scrollbar>
    <v-contextmenu ref="contextMenuRef">
      <v-contextmenu-item v-for="item in contextList" :key="item.key">
        <div class="contextmenu-item" @click="contextClick(item.key)">{{ item.title }}</div>
      </v-contextmenu-item>
    </v-contextmenu>
  </div>
</template>
<script setup lang="ts">
  import { ref, reactive, onActivated, onDeactivated, watch, computed, ComputedRef } from 'vue'
  import { useStore } from 'vuex'
  import bus from '@/utils/bus'
  import { ElMessage, ElMessageBox } from 'element-plus'
  import { saveSheet, deleteSheet, updateSheet } from '@/api/sheet'

  // eslint-disable-next-line no-undef
  defineOptions({
    name: 'MenuList'
  })

  interface SheetItem {
    title: string
    key: string | number
    icon?: string
  }

  const props = withDefaults(
    defineProps<{
      createdSheetList: SheetItem[]
    }>(),
    {
      createdSheetList: () => []
    }
  )
  const store = useStore()
  // 默认展开所有
  const activeNames: ComputedRef<string[]> = computed(() => {
    return menuList.value.map((item: any) => item.key)
  })

  // 当前高亮的菜单节点
  const currentNode = reactive({ title: '', key: '' })
  // 重置当前节点
  const resetMenu = () => {
    Object.assign(currentNode, { title: '', key: '' })
  }
  const menuList = ref<any>([
    {
      title: '在线音乐',
      key: 'onlineMusic',
      children: [
        {
          title: '推荐',
          key: 'recommend',
          icon: ''
        },
        {
          title: '音乐馆',
          key: 'musicHall',
          icon: ''
        },
        {
          title: '视频',
          key: 'video',
          icon: ''
        },
        {
          title: '电台',
          key: 'radioStation',
          icon: ''
        }
      ]
    },
    {
      title: '我的音乐',
      key: 'myMusic',
      children: [
        {
          title: '我喜欢',
          key: 'myLike',
          icon: ''
        },
        {
          title: '最近播放',
          key: 'recentPlays',
          icon: ''
        }
      ]
    },
    {
      title: '创建的歌单',
      key: 'createdSongs',
      children: []
    }
  ])

  watch(
    () => props.createdSheetList,
    val => {
      menuList.value.at(-1)!.children = val
    }
  )

  const menuClick = (data: SheetItem) => {
    Object.assign(currentNode, data)
    store.commit('addLog', data.key)
  }

  onActivated(() => {
    // 监听日志的前进回退功能
    bus.on('logChange', (val: any) => {
      menuList.value.forEach((item: any) => {
        item.children.forEach((item: any) => {
          if (item.key === val.key) {
            Object.assign(currentNode, item)
          }
        })
      })
    })
    bus.on('resetMenu', resetMenu)
  })

  onDeactivated(() => {
    bus.off('resetMenu')
    bus.off('logChange')
  })

  // 右侧动态组件的联动
  watch(currentNode, () => {
    if (currentNode.key) bus.emit('menuChange', currentNode.key)
  })

  let inputValue = ''
  // 增加歌单
  const addSongSheet = () => {
    ElMessageBox.prompt('请输入歌单的名称', '添加歌单', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      inputPattern: /^[\S]{1,16}$/,
      inputValue,
      inputErrorMessage: '歌单名称长度为1至16个字符',
      inputPlaceholder: '请输入歌单名称'
    }).then(({ value }) => {
      if (inputValue) {
        updateSheet({
          id: activeContextNode.key,
          sheetName: value
        }).then(res => {
          const sheetList = menuList.value.at(-1).children
          const index = sheetList.findIndex((item: any) => item.key === activeContextNode.key)
          sheetList[index].title = value
          ElMessage({
            message: '修改歌单成功',
            type: 'success'
          })
          inputValue = ''
        })
      } else {
        saveSheet({
          userId: store.state.userInfo.userId,
          sheetName: value
        }).then((res: any) => {
          const obj = {
            title: res.sheetName,
            key: res.id,
            icon: ''
          }
          menuList.value.at(-1).children.unshift(obj)
          ElMessage({
            message: '新增歌单成功',
            type: 'success'
          })
          inputValue = ''
        })
      }
    })
  }
  const contextList = ref([
    { title: '播放', icon: '', key: 'play' },
    { title: '删除', icon: '', key: 'delete' },
    { title: '重命名', icon: '', key: 'rename' },
    { title: '恢复歌单', icon: '', key: 'resume' }
  ])

  // 右键菜单
  const contextMenuRef = ref<any>(null)
  // 右键菜单当前操作的节点
  let activeContextNode: SheetItem = { title: '', key: '' }

  const clickRight = (e: MouseEvent, item: SheetItem) => {
    if (typeof item.key === 'number') {
      menuClick(item)
      activeContextNode = item
      contextMenuRef.value.show({ left: e.clientX, top: e.clientY })
    }
    document.addEventListener('click', contextMenuRef.value.hide)
  }

  const contextClick = (key: string) => {
    switch (key) {
      case 'play':
        bus.emit('handleMenuPlay')
        break
      case 'delete':
        ElMessageBox.confirm('您确定删除吗?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'error'
        }).then(() => {
          deleteSheet(activeContextNode.key).then(() => {
            const sheetList = menuList.value.at(-1).children
            // 被删除元素的索引
            const deleteIndex = sheetList.findIndex(
              (item: SheetItem) => item.key === activeContextNode.key
            )
            sheetList.splice(deleteIndex, 1)
            ElMessage({
              message: '删除歌单成功',
              type: 'success'
            })
            // 一个歌单都没有了则回到推荐界面
            if (!sheetList.length) {
              currentNode.key = 'recommend'
              return
            }
            // 如果删除是当前的,后面有就高亮下一个否则高亮第一个
            if (activeContextNode.key === parseInt(currentNode.key)) {
              currentNode.key =
                deleteIndex === sheetList.length ? sheetList[0].key : sheetList[deleteIndex].key
            }
          })
        })
        break
      case 'rename':
        inputValue = activeContextNode.title
        addSongSheet()
        break
      case 'resume':
        break
    }
  }

  defineExpose({
    menuList
  })
</script>

<style lang="scss" scoped>
  .contextmenu-item {
    width: 110px;
    height: 22px;
    line-height: 22px;
  }
  .menu {
    width: 230px;
    background-color: #f0f0f0;
    .logo {
      height: $menuLogoHeight;
      img {
        width: 60px;
        height: 60px;
      }
    }
    .list {
      :deep(.el-collapse-item__header) {
        font-size: 16px;
        padding-left: 20px;
        padding-right: 10px;
        background-color: #f0f0f0;
        &.focusing:focus:not(:hover) {
          color: #000;
        }
      }
      :deep(.el-collapse-item__wrap) {
        background-color: #f0f0f0;
      }
      :deep(.el-collapse-item__content) {
        padding-bottom: 0;
      }
      .menu-item {
        padding-left: 20px;
        // color: #303030;
        height: 35px;
        line-height: 35px;
        margin: 0 15px 0 20px;
        border-radius: 10px;
        margin-bottom: 15px;
        transition: 0.2s;
        &:hover {
          background-color: #d8d8d8;
        }
        &.active {
          color: #fff;
          background-color: $musicColor;
        }
      }
    }
  }
</style>
